﻿using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using DigitalRune.Windows.TextEditor.Actions;
using FunctionalCLR.Core;
using Gajatko.IniFiles.Light;
using Zove.Desktop.Tools;
using Zove.Runtime;
using WeifenLuo.WinFormsUI.Docking;

namespace Zove.Desktop {
    public partial class Form1 : Form {

        private int untitledCount = 0;

        public string Status {
            get {
                return this.StatusBar.Text;
            }
            set {
                this.StatusBar.Text = value;
            }
        }

        public Form1() {
            InitializeComponent();

            this.tsbNew.Click += new EventHandler(exitToolStripMenuItem_Click);
            this.tsbOpen.Click += new EventHandler(forEditToolStripMenuItem_Click);
            //this.tsbOpenForRun.Click += new EventHandler(forRunToolStripMenuItem_Click);
            this.tsbSave.Click += new EventHandler(saveToolStripMenuItem_Click);
            this.tsbRun.Click += new EventHandler(runToolStripMenuItem1_Click);
            this.DragDrop += new DragEventHandler(Form1_DragDrop);
            this.DragEnter += new DragEventHandler(From1_DragEnter);

            // loads functions
            string str = ZoveDependencyManager.Instance.ToString();

            LoadCLassToMenu();
        }

        public void Form1_DragDrop(object sender, DragEventArgs e) {
            string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);

            foreach (string file in files) {
                if (file.EndsWith(".zoom")) {
                    OpenEditWindow(file);
                } else if (file.EndsWith(".zql")) {
                    OpenQueryWindow(file);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public QueryWindow OpenQueryWindow() {
            QueryWindow qw = new QueryWindow();
            this.InitQueryWindow(qw);            

            return qw;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="qw"></param>
        public void InitQueryWindow(QueryWindow qw) {
            qw.MdiParent = this;
            qw.FormClosing += new FormClosingEventHandler(RemoveWindowItem);
            qw.Show();

            AddWindowMenuItem(qw, WindowType.Run);
        }

        /// <summary>
        /// Open the query window.
        /// </summary>
        /// <param name="file"></param>
        public void OpenQueryWindow(string file) {
            QueryWindow qw = new QueryWindow(file);
            qw.Content = File.ReadAllText(file);

            this.InitQueryWindow(qw);
        }

        public void From1_DragEnter(object sender, DragEventArgs e) {
            if (e.Data.GetDataPresent(DataFormats.FileDrop, false) == true)
                e.Effect = DragDropEffects.All;
        }

        public void RemoveWindowItem(object source, FormClosingEventArgs e) {
            Form form = (Form)source;
            foreach (ToolStripItem item in windowToolStripMenuItem.DropDownItems) {
                if (item.Name == form.Text) {
                    windowToolStripMenuItem.DropDownItems.Remove(item);
                    DesktopFormContext.Context.Remove(form);
                    return;
                }
            }
        }

        public bool AddMenuItems(ToolStripMenuItem item, DirectoryInfo di) {
            int index = 1;
            bool c = false;
            foreach (FileInfo ci in di.GetFiles("*.zoom")) {
                c = true;
                ToolStripMenuItem current = new ToolStripMenuItem();

                current.Name = ci.Name.Split('.')[0];
                current.Text = current.Name;
                index++;

                ToolStripMenuItem forRun = new ToolStripMenuItem("&Run");
                forRun.Click += new EventHandler(ForRunMenuItemClick);
                current.DropDownItems.Add(forRun);

                ToolStripMenuItem forEdit = new ToolStripMenuItem("&Edit");
                forEdit.Click += new EventHandler(ForEditMenuItemClick);
                current.DropDownItems.Add(forEdit);

                item.DropDownItems.Add(current);
            }

            foreach (DirectoryInfo sdi in di.GetDirectories()) {
                ToolStripMenuItem i = new ToolStripMenuItem();
                i.Name = sdi.Name;
                i.Text = sdi.Name;
                item.DropDownItems.Add(i);

                FileInfo[] info = sdi.GetFiles("library.ini");
                if (info.Length > 0) {
                    IniFileLight iniFile = new IniFileLight(info[0].FullName);
                    if (iniFile.Sections["overview"] != null) {
                        string icon = iniFile.Sections["overview"]["icon"];
                        if (File.Exists(icon)) {
                            i.Image = Image.FromFile(icon);
                        }
                    }
                }

                if (AddMenuItems(i, sdi)) {
                    c = true;
                } else {
                    item.DropDownItems.Remove(i);
                }
            }

            return c;
        }

        public void LoadCLassToMenu() {
            string[] classPath = Utils.ModelPath.Split(';');

            foreach (string cp in classPath) {
                DirectoryInfo di = new DirectoryInfo(cp);
                AddMenuItems(modelsToolStripMenuItem, di);
            }
        }

        private void exitToolStripMenuItem1_Click(object sender, EventArgs e) {
            this.Close();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e) {

        }

        private void runToolStripMenuItem1_Click(object sender, EventArgs e) {
            if (this.ActiveMdiChild != null
                && this.ActiveMdiChild.GetType().GetInterface(typeof(IDesktopForm).Name, true) != null) {
                ((IDesktopForm)this.ActiveMdiChild).Execute();
            }
        }

        private int windowCount = 0;

        public void AddWindowMenuItem(Form form, WindowType type) {
            int index = this.windowCount + 1;

            ToolStripMenuItem item = new ToolStripMenuItem();
            item.Name = form.Text;
            item.Text = "&" + index.ToString() + " " + form.Text;
            item.Click += new EventHandler(WindowItem_Click);

            index = windowToolStripMenuItem.DropDownItems.Add(item);
            DesktopFormContext.Context.Add(form);
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e) {
            if (this.ActiveMdiChild == null) {
                return;
            }

            IDesktopForm dw = (IDesktopForm)this.ActiveMdiChild;

            if (string.IsNullOrEmpty(dw.GetFileName())) {
                saveAsToolStripMenuItem_Click(sender, e);
            } else {
                dw.Save(dw.GetFileName());
            }
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e) {
            //MessageBox.Show(
            //    string.Format("{0}\nRuntime version {1}",
            //        this.Text,
            //        typeof(Zove.Runtime.Solution).Assembly.GetName().Version));
            AboutBox1 f = new AboutBox1();

            f.MdiParent = this;
            f.Show();
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e) {
            IDesktopForm dw = (IDesktopForm)this.ActiveMdiChild;
            if (dw == null) {
                return;
            }

            string initPath = Utils.ModelPath;
            SaveFileDialog dialog = new SaveFileDialog();

            dialog.Filter = dw.GetFileFilter();
            dialog.InitialDirectory = initPath.Split(';')[0];
            if (dialog.ShowDialog() == DialogResult.OK) {
                string fileName = dialog.FileName.Trim();

                dw.Save(fileName);
            }
        }

        private void forRunToolStripMenuItem_Click(object sender, EventArgs e) {
            string initPath = Utils.ModelPath;
            OpenFileDialog dialog = new OpenFileDialog();

            dialog.Filter = "Zoom Source (*.zoom) | *.zoom";
            dialog.InitialDirectory = initPath;

            if (dialog.ShowDialog() == DialogResult.OK) {
                int lastDot = dialog.FileName.LastIndexOf('.');
                int last = dialog.FileName.LastIndexOf('\\');
                string name = dialog.FileName.Substring(last + 1, lastDot - last - 1);

                OpenRunWindow(name);
            }
        }

        private void forEditToolStripMenuItem_Click(object sender, EventArgs e) {
            string initPath = Utils.ModelPath;
            OpenFileDialog dialog = new OpenFileDialog();

            dialog.Filter = "Zoom Source (*.zoom) | *.zoom";
            dialog.InitialDirectory = initPath.Split(';')[0];

            if (dialog.ShowDialog() == DialogResult.OK) {
                if (DesktopFormContext.Context.ContainsKey(dialog.FileName)) {
                    DesktopFormContext.Context[dialog.FileName].BringToFront();
                } else {
                    OpenEditWindow(dialog.FileName);
                }
            }
        }

        public void ForRunMenuItemClick(object source, EventArgs e) {
            ToolStripMenuItem item = (ToolStripMenuItem)source;

            OpenRunWindow(item.OwnerItem.Name);
        }

        private void OpenRunWindow(string className) {
            try {
                RunWindow rw = new RunWindow(className);
                rw.MdiParent = this;
                rw.FormClosing += new FormClosingEventHandler(RemoveWindowItem);
                rw.Show();

                AddWindowMenuItem(rw, WindowType.Run);
            } catch (Exception ex) {
                MessageBox.Show(ex.Message);
            }
        }

        public void ForEditMenuItemClick(object source, EventArgs e) {
            ToolStripMenuItem item = (ToolStripMenuItem)source;

            OpenEditWindow(item.OwnerItem.Name + ".zoom");
        }

        public EditingForm OpenEditWindow(string p) {
            EditingForm editor = null;

            if (!string.IsNullOrEmpty(p)) {
                DefaultClassFinder finder = new DefaultClassFinder();
                int index = p.IndexOf('.');

                string className = p;
                if (index > 0) {
                    className = p.Split('.')[0];
                }
                p = finder.GetLocation(className);

                if (System.IO.File.Exists(p) == false) {
                    MessageBox.Show(className + " does not exist");
                    return null;
                }
                editor = new EditingForm(p);
                editor.Text = p;
            } else {
                untitledCount++;
                editor = new EditingForm();
                editor.Text = "Untilted " + untitledCount;
            }

            ShowWindow(editor);

            return editor;
        }

        public void ShowWindow(Form editor) {
            //if (dockPanel1.DocumentStyle == DocumentStyle.SystemMdi) {
                editor.MdiParent = this;
                editor.FormClosing += new FormClosingEventHandler(RemoveWindowItem);
                editor.Show();
            //} else {
                //editor.Show(dockPanel1);
            //}
            AddWindowMenuItem(editor, WindowType.Run);
        }

        public void WindowItem_Click(object source, EventArgs e) {
            ToolStripMenuItem item = (ToolStripMenuItem)source;

            DesktopFormContext.Context[item.Text].BringToFront();
        }

        private void tsbNew_Click(object sender, EventArgs e) {
            OpenEditWindow(string.Empty);
        }

        private void toolStripMenuItem2_Click(object sender, EventArgs e) {
            Cut cut = new Cut();
            Execute(cut);
        }

        public void Execute(AbstractEditAction action) {
            IDesktopForm form = (IDesktopForm)this.ActiveMdiChild;
            if (form == null) {
                return;
            }

            action.Execute(form.GetTextEditorControl());
        }

        private void pasteToolStripMenuItem_Click(object sender, EventArgs e) {
            Paste paste = new Paste();
            this.Execute(paste);
        }

        private void copyToolStripMenuItem_Click(object sender, EventArgs e) {
            Copy copy = new Copy();
            this.Execute(copy);
        }

        private void toolStripMenuItem3_Click(object sender, EventArgs e) {
            if (this.ActiveMdiChild == null) {
                return;
            }

            SaveFileDialog dialog = new SaveFileDialog();

            if (dialog.ShowDialog() == DialogResult.OK) {
                ((IDesktopForm)this.ActiveMdiChild).Save(dialog.FileName);
            }
        }

        private void preferencesToolStripMenuItem1_Click(object sender, EventArgs e) {
            PreferencesForm form = new PreferencesForm();

            form.ShowDialog();
        }

        private void undoToolStripMenuItem_Click(object sender, EventArgs e) {
            Undo undo = new Undo();
            this.Execute(undo);
        }

        private void selectAllToolStripMenuItem_Click(object sender, EventArgs e) {
            SelectWholeDocument selectAll = new SelectWholeDocument();
            Execute(selectAll);
        }

        private void redoToolStripMenuItem_Click(object sender, EventArgs e) {
            Redo redo = new Redo();
            this.Execute(redo);
        }

        private void clearInputToolStripMenuItem_Click(object sender, EventArgs e) {
            if (this.ActiveMdiChild != null && this.ActiveMdiChild.GetType() == typeof(RunWindow)) {
                RunWindow rw = (RunWindow)this.ActiveMdiChild;
                rw.ClearInput();
            }
        }

        private void queryToolStripMenuItem_Click(object sender, EventArgs e) {
            this.OpenQueryWindow();
        }

        private void tsbSave_Click(object sender, EventArgs e) {
            this.saveToolStripMenuItem_Click(sender, e);
        }

        private void tsbNew_Click_1(object sender, EventArgs e) {
            this.OpenEditWindow(string.Empty);
        }

        private void expressionEvaluatorToolStripMenuItem_Click(object sender, EventArgs e) {
            Tools.ExpressionEvaluatorForm f = new Zove.Desktop.Tools.ExpressionEvaluatorForm();

            f.MdiParent = this;
            f.Show();
        }

        private void arrangeWindowsToolStripMenuItem_Click(object sender, EventArgs e) {

        }

        private void closeAllToolStripMenuItem_Click(object sender, EventArgs e) {
            foreach (Form f in this.MdiChildren) {
                f.Close();
            }
        }

        private void classStatisticsToolStripMenuItem_Click(object sender, EventArgs e) {
            ClassStatisticsForm f = null;

            if (ActiveMdiChild != null) {
                RuntimeModel rm = null;
                if (ActiveMdiChild.GetType() == typeof(EditingForm)) {
                    EditingForm ef = (EditingForm)ActiveMdiChild;
                    rm = ZoveDependencyManager.Instance.RuntimeModelLoader.Load(ef.ClassName);
                } else if (ActiveMdiChild.GetType() == typeof(RunWindow)) {
                    RunWindow rw = (RunWindow)ActiveMdiChild;
                    rm = ZoveDependencyManager.Instance.RuntimeModelLoader.Load(rw.ClassName);
                } else {
                    return;
                }

                f = new ClassStatisticsForm(rm);
            } else {
                MessageBox.Show("Please open a class for edit or run to proceed.");
                return;
            }

            f.MdiParent = this;
            f.Show();
        }

        private void messagesToolStripMenuItem_Click(object sender, EventArgs e) {
            if (MessageForm.Instance == null) {
                MessageForm.Instance = new MessageForm();
                MessageForm.Instance.MdiParent = this;
            }

            MessageForm.Instance.ShowInsideMdiParent();
        }

        private void rootFinderToolStripMenuItem_Click(object sender, EventArgs e) {
            RootFinderForm f = new RootFinderForm();

            f.MdiParent = this;
            f.Show();
        }

        private void equationSetSolverToolStripMenuItem_Click(object sender, EventArgs e) {
            EquationGroupSolverForm f = new EquationGroupSolverForm();

            f.MdiParent = this;
            f.Show();
        }

        private void forQueryToolStripMenuItem_Click(object sender, EventArgs e) {
            OpenFileDialog f = new OpenFileDialog();

            f.Filter = "Zoom Query Language File (*.zql) | *.zql";
            if (f.ShowDialog() == DialogResult.OK) {
                OpenQueryWindow(f.FileName);
            }
        }

        public void CheckModel() {
            if (this.ActiveMdiChild != null
                && this.ActiveMdiChild.GetType().Equals(typeof(EditingForm))) {
                EditingForm f = (EditingForm)this.ActiveMdiChild;

                try {
                    IRuntimeModelLoader loader
                        = ZoveDependencyManager.Instance.RuntimeModelLoader;
                    //loader.GetLogger().ClearAll();

                    RuntimeModel rm = loader.LoadFromSource(f.Source);
                    //if (loader.GetLogger().GetErrorMessages().Count > 0) {
                    //    if (MessageForm.Instance == null) {
                    //        MessageForm.Instance = new MessageForm();
                    //        MessageForm.Instance.MdiParent = this;
                    //    }

                    //    MessageForm.Instance.ShowMessages(
                    //        "Errors", loader.GetLogger().GetErrorMessages());
                    //    return;
                    //} else {
                    //    MessageBox.Show("The model is well defined.");
                    //}
                } catch (Exception ex) {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private void tsCheckModel_Click(object sender, EventArgs e) {
            CheckModel();
        }

        private void checkToolStripMenuItem_Click(object sender, EventArgs e) {
            CheckModel();
        }

        private void toolStripMenuItem5_Click(object sender, EventArgs e) {
            if (this.ActiveMdiChild != null) {
                this.ActiveMdiChild.Close();
            }
        }

        private void toolStripButton1_Click(object sender, EventArgs e) {
            OpenQueryWindow();
        }

        private void modelToolStripMenuItem_Click(object sender, EventArgs e) {
            this.OpenEditWindow(string.Empty);
        }

        private void programToolStripMenuItem_Click(object sender, EventArgs e) {
            OpenProgrammingWindow();
        }

        public void OpenProgrammingWindow() {
            ProgrammingEditor pe = new ProgrammingEditor();

            ShowWindow(pe);
        }

        public void OpenProgrammingWindow(string fileName) {
            ProgrammingEditor pe = new ProgrammingEditor(fileName);

            ShowWindow(pe);
        }

        private void queryToolStripMenuItem1_Click(object sender, EventArgs e) {
            OpenQueryWindow();
        }

        private void programmingToolStripMenuItem_Click(object sender, EventArgs e) {
            OpenFileDialog f = new OpenFileDialog();

            if (f.ShowDialog() == DialogResult.OK) {
                ProgrammingEditor pe = new ProgrammingEditor(f.FileName);

                ShowWindow(pe);
            }
        }

        private void outputToolStripMenuItem_Click(object sender, EventArgs e) {
            //ConsoleWindow.Instance.Show();
        }

        private void interactiveModeToolStripMenuItem_Click(object sender, EventArgs e) {
            InteractiveMode i = new InteractiveMode();

            i.MdiParent = this;
            i.Show();
        }

        private void refreshMenuToolStripMenuItem_Click(object sender, EventArgs e) {
            this.modelsToolStripMenuItem.DropDownItems.Clear();
            LoadCLassToMenu();
        }

        private void toolStripMenuItem6_Click(object sender, EventArgs e) {
            Delete action = new Delete();
            this.Execute(action);
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e) {
            string initPath = Utils.ModelPath;
            OpenFileDialog dialog = new OpenFileDialog();

            dialog.Filter = "All Zoom Files (*.zoom; *.fpz; *.zql)|*.zoom;*.fpz;*.zql|Modeling Files (*.zoom) |*.zoom|Programming Files (*.fpz)|*.fpz|Query Files (*.zql)|*.zql|OML Files (*.oml)|*.oml|Text Files (*.txt)|*.txt|INI Files (*.ini)|*.ini|XML Files (*.xml)|*.xml|All Files (*.*)|*.*";
            dialog.InitialDirectory = initPath;

            if (dialog.ShowDialog() == DialogResult.OK) {
                int lastDot = dialog.FileName.LastIndexOf('.');
                int last = dialog.FileName.LastIndexOf('\\');

                string extension = string.Empty;
                string fileName = dialog.FileName;

                if (lastDot > 0) {
                    fileName = dialog.FileName.Substring(last + 1, lastDot - last - 1);
                    extension = dialog.FileName.Substring(lastDot, dialog.FileName.Length - lastDot);
                }

                switch (extension) {
                    case ".zoom":
                        OpenEditWindow(fileName);
                        break;
                    case ".fpz":
                        OpenProgrammingWindow(dialog.FileName);
                        break;
                    case ".zql":
                        OpenQueryWindow(dialog.FileName);
                        break;
                    case ".oml":
                        OpenOMLWindow(dialog.FileName);
                        break;
                    case ".txt":
                        OpenTextEditWindow(dialog.FileName, "Text");
                        break;
                    case ".xml":
                        OpenTextEditWindow(dialog.FileName, "Xml");
                        break;
                    default:
                        OpenTextEditWindow(dialog.FileName, "Text");
                        break;
                }
            }
        }

        private void OpenTextEditWindow(string p, string type) {
            TextEditor te = new TextEditor(p, type);

            ShowWindow(te);
        }

        protected void OpenOMLWindow(string fileName) {
            OMLEditor oe = new OMLEditor(fileName);

            this.ShowWindow(oe);
        }

        private void toolStripMenuItem7_Click(object sender, EventArgs e) {
            foreach (Form f in this.MdiChildren) {
                if (f is IDesktopForm) {
                    IDesktopForm idf = f as IDesktopForm;
                    if (string.IsNullOrEmpty(idf.GetFileName())) {
                        OpenFileDialog d = new OpenFileDialog();

                        if (d.ShowDialog() == DialogResult.OK) {
                            idf.Save(d.FileName);
                        }
                    } else {
                        idf.Save(idf.GetFileName());
                    }
                }
            }
        }

        private void oMLToolStripMenuItem_Click(object sender, EventArgs e) {
            OMLEditor oe = new OMLEditor();

            this.ShowWindow(oe);
        }

        private void toolbarToolStripMenuItem_Click(object sender, EventArgs e) {
            this.toolStrip1.Visible = this.toolbarToolStripMenuItem.Checked = !this.toolbarToolStripMenuItem.Checked;
        }

        private void statusbarToolStripMenuItem_Click(object sender, EventArgs e) {
            this.statusStrip1.Visible = this.statusbarToolStripMenuItem.Checked = !this.statusbarToolStripMenuItem.Checked;
        }
    }
}
